/*
 * Copyright (c) 2012 OptiCare Systems Ltd
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 *
 * Authors: Kevin Martin (kev82@khn.org.uk)
 */
#ifndef __INT_GEARMAN_WORKER_HEADER__
#define __INT_GEARMAN_WORKER_HEADER__

#include <string>
#include <libgearman/gearman.h>
#include <boost/shared_ptr.hpp>
#include <stdexcept>
#include <vector>

/**
 * This is a base class used to implement the actual function, workerfunction
 * is passed a pointer to this class which is then used to call the
 * implementation method of the child.
 *
 * implementation() can set its return values by accessing the retData_
 * variable. On sucess implementation() should return true, on failure it
 * should return false.
 */
class GearmanWorkerFunction
{
	friend void *workerfunction(gearman_job_st *job, void *context,
	 size_t *result_size, gearman_return_t *ret_ptr);
protected:
	std::string name_;
	std::string retData_;
	const std::string &getReturn() { return retData_; }
	virtual bool implementation(const std::string &data) =0;
public:
	GearmanWorkerFunction(const std::string &name) : name_(name), retData_("") {}
	const std::string &name() const { return name_; }
};

/**
 * This is an internal wrapper around gearman_worker_st to make sure it is allocated and
 * destroyed correctly.
 */
struct _GearmanWorkerStruct_
{
private:
	gearman_worker_st *gw_;

	_GearmanWorkerStruct_ &operator=(const _GearmanWorkerStruct_ &) {
		throw std::logic_error("Unreachable Code");
	}
	_GearmanWorkerStruct_(const _GearmanWorkerStruct_ &) {
		throw std::logic_error("Unreachable Code");
	}
public:
	operator gearman_worker_st *() { return gw_; }

	_GearmanWorkerStruct_();
	~_GearmanWorkerStruct_();
};

/**
 * This represents a single german worker. A woker function should be passed to it on construction,
 * then Run should be called. The code will then repeatedly server requests to the named function
 *
 * Ignore the terminate_ member, it has not been implemented
 */
class GearmanWorker
{
private:
	_GearmanWorkerStruct_ gw_;
	std::vector<boost::shared_ptr<GearmanWorkerFunction> > wfs_;
	std::string host_;
	int port_;
	bool terminate_;
	
	void addServer();
	void registerFunction();
	void unregisterAll();
	void runloop();
public:
	GearmanWorker(const boost::shared_ptr<GearmanWorkerFunction> wf);
	GearmanWorker(const std::vector<boost::shared_ptr<GearmanWorkerFunction> > &wfs);

	void Run();
};

#endif
